﻿@page "/users"

@using Gurux.DLMS.AMI.Shared.DIs

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Gurux.DLMS.AMI.Shared.DTOs.Authentication
@using Gurux.DLMS.AMI.Shared.Rest
@using Microsoft.AspNetCore.SignalR.Client
@using Gurux.DLMS.AMI.Shared
@using Gurux.DLMS.AMI.Shared.Enums
@using Gurux.DLMS.AMI.Client.Helpers
@using Gurux.DLMS.AMI.Module

@attribute [Authorize(Roles = "Admin, UserManager")]
@inject NavigationManager NavigationManager
@inject HttpClient Http
@inject IGXNotifier2 Notifier
@implements IDisposable
@implements IAmiComponent
@if (Title)
{
    <PageTitle>@Properties.Resources.UsersTitle</PageTitle>
}

<AuthorizeView Roles=@GXRoles.ToString(GXRoles.Admin, GXRoles.UserManager)>
    <MenuControl RightCorner="true">
        <ChildContent>
            <MenuItem Text="@Properties.Resources.Add" Icon="oi oi-plus" OnClick="@OnAdd" />
            <MenuItem Text="@Properties.Resources.Remove" Icon="oi oi-trash" OnClick="@OnRemove" />
        </ChildContent>
    </MenuControl>
</AuthorizeView>

<GXTable @ref="table"
         Context="user"
         ItemsProvider="@GetItems"
         SelectionMode="SelectionMode.Multiple"
         Filter="@Filter"
         ShowAllUsers="@Header"
         ShowRemoved="@Header"
         Columns="@Columns"
         CanEdit="@CanEdit"
         OnSearch="@Updated">
    <FilterContent>
        <th>
            <input class="form-control" placeholder="Filter by given name..."
                   @onchange="@((ChangeEventArgs __e) => filter.GivenName = Convert.ToString(__e.Value))" />
        </th>
        <th>
            <input class="form-control" placeholder="Filter by surname..."
                   @onchange="@((ChangeEventArgs __e) => filter.Surname = Convert.ToString(__e.Value))" />
        </th>
        <th>
            <input class="form-control" type="text" placeholder="Filter by email..."
                   @onchange="@((ChangeEventArgs __e) => filter.Email = Convert.ToString(__e.Value))" />
        </th>
        <th>
            <input class="form-control" type="text" placeholder="Filter by email confirmed..."
                   @onchange="@((ChangeEventArgs __e) => filter.EmailConfirmed = StatusTile.ToBoolean(__e.Value))" />
        </th>
        <th>
            <input class="form-control" type="text" placeholder="Filter by role..."
                   @onchange="@((ChangeEventArgs __e) => @UpdateRoles(Convert.ToString(__e.Value)))" />
        </th>
        <th>
            <input class="form-control" placeholder="按创建时间..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.CreationTime = StatusTile.ToDateTime(__e.Value))" />
        </th>
        <th>
            <input class="form-control" placeholder="Filter by Updated..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.Updated = StatusTile.ToDateTime(__e.Value))" />
        </th>
        <th>
            <input class="form-control" placeholder="Filter by last login..."
                   type="datetime-local"
                   @onchange="@((ChangeEventArgs __e) => filter.LastLogin = StatusTile.ToDateTime(__e.Value))" />
        </th>
        <th>
            <input class="form-control" placeholder="Filter by access failed count..."
                   @onchange="@((ChangeEventArgs __e) => filter.AccessFailedCount = StatusTile.ToInt32(__e.Value))" />
        </th>
    </FilterContent>
    <MenuContent>
        <AuthorizeView Roles=@GXRoles.ToString(GXRoles.Admin, GXRoles.ScriptGroupManager)>
            <ContextMenuItem Text="@Properties.Resources.Edit" Icon="oi oi-pencil" OnClick="@OnEdit"></ContextMenuItem>
            <ContextMenuItem Text="@Properties.Resources.Remove" Icon="oi oi-trash" OnClick="@OnRemove"></ContextMenuItem>
            <ContextMenuItem Text="@Properties.Resources.Actions" Icon="oi oi-info" OnClick="async () => OnActions()"></ContextMenuItem>
            <!--TODO:
            <ContextMenuItem Text="@Properties.Resources.Agents" Icon="oi oi-wifi" OnClick="async () => OnAgents()"></ContextMenuItem>
            -->
        </AuthorizeView>
    </MenuContent>
    <HeaderContent>
        <Th Id="GivenName">@Properties.Resources.GivenName</Th>
            <Th Id="Surname">@Properties.Resources.Surname</Th>
            <Th Id="Email">@Properties.Resources.Email</Th>
            <Th Id="EmailConfirmed">@Properties.Resources.EmailConfirmed</Th>
            <th>@Properties.Resources.Roles</th>
        <Th Id="CreationTime" SortMode="SortMode.Descending">@Properties.Resources.CreationTime</Th>
            <Th Id="Updated">@Properties.Resources.Updated</Th>
            <Th Id="LastLogin">@Properties.Resources.LastLogin</Th>
            <Th Id="AccessFailed">@Properties.Resources.AccessFailed</Th>
        </HeaderContent>
        <ItemContent>
            <td>@user.GivenName</td>
        <td>@user.Surname</td>
        <Td Link="@("User/Edit/" + user.Id)">@user.Email</Td>
            <td>@user.EmailConfirmed</td>
        <td>@RolesToString(user.Roles)</td>
        <td>@user.CreationTime</td>
        <td>@user.Updated</td>
        <td>@user.LastLogin</td>
        <td>@user.AccessFailedCount</td>
    </ItemContent>
</GXTable>
<br />
<Confirm @ref="DeleteConfirmation"
         ConfirmationChanged="OnDeleteConfirmation"
         OkTitle="@Properties.Resources.Remove"
         ConfirmationMessage=""
         ConfirmationTitle="@Properties.Resources.AreYouSureYouWantToDeleteSelectedItems">
</Confirm>

@code {
    /// <summary>
    /// Selected user ID.
    /// </summary>
    [Parameter]
    public Guid? Id { get; set; }


    /// <inheritdoc />
    public string Name
    {
        get
        {
            return Gurux.DLMS.AMI.Client.Properties.Resources.UsersTitle;
        }
    }

    /// <inheritdoc />
    public Type? ConfigurationUI
    {
        get
        {
            return null;
        }
    }

    /// <inheritdoc />
    public string? Icon
    {
        get
        {
            return "oi oi-people";
        }
    }

    /// <summary>
    /// Amount of the users shown on the view.
    /// </summary>
    [Parameter]
    public int Count { get; set; } = 0;

    /// <summary>
    /// Is filter shown.
    /// </summary>
    [Parameter]
    public bool Filter { get; set; } = true;

    /// <summary>
    /// Is header shown.
    /// </summary>
    [Parameter]
    public bool Header { get; set; } = true;

    /// <summary>
    /// Is edit allowed.
    /// </summary>
    [Parameter]
    public bool CanEdit { get; set; } = true;

    /// <summary>
    /// Available columns.
    /// </summary>
    [Parameter]
    public string[]? Columns { get; set; }

    /// <summary>
    /// Is title shown.
    /// </summary>
    [Parameter]
    public bool Title { get; set; } = true;

    /// <summary>
    /// Convert role array to string.
    /// </summary>
    /// <param name="roles"></param>
    /// <returns></returns>
    private static string? RolesToString(List<string>? roles)
    {
        if (roles == null)
        {
            return null;
        }
        string str = string.Join(',', roles);
        //Truncate if string is too long...
        if (str.Length > 30)
        {
            str = str.Substring(0, 30) + "...";
        }
        return str;
    }

    private void UpdateRoles(string roles)
    {
        if (filter != null && filter.Roles != null)
        {
            filter.Roles.Clear();
            if (!string.IsNullOrEmpty(roles))
            {
                filter.Roles.AddRange(roles.Split(',', StringSplitOptions.RemoveEmptyEntries));
            }
        }
    }

    /// <summary>
    /// User filter.
    /// </summary>
    private GXUser filter = new GXUser();

    /// <summary>
    /// User is verified before user is removed.
    /// </summary>
    protected ConfirmBase? DeleteConfirmation;

    /// <summary>
    /// Table reference.
    /// </summary>
    protected GXTable<GXUser>? table;

    /// <summary>
    /// Update table.
    /// </summary>
    protected async Task Updated()
    {
        try
        {
            if (table != null)
            {
                Notifier?.ClearStatus();
                await table.RefreshDataAsync(true);
            }
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    protected override async Task OnInitializedAsync()
    {
        //Wait until table is loaded. Don't remove this or table is null and last settings are not available.
        await Task.Delay(1);
        try
        {
            if (Notifier == null)
            {
                throw new ArgumentException(Properties.Resources.InvalidNotifier);
            }
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            object? data = Notifier.GetData("users");
            if (data is GXUser u && table != null)
            {
                table.Active = u;
            }
            Notifier.On<IEnumerable<GXUser>>(this, nameof(IGXHubEvents.UserUpdate), async (user) =>
            {
                await Updated();
            });
            Notifier.On<IEnumerable<GXUser>>(this, nameof(IGXHubEvents.UserDelete), async (user) =>
            {
                await Updated();
            });
            Notifier.Clear();
            Notifier.UpdateButtons();
            if (table != null && Id != null)
            {
                //Get last selected item.
                table.Active = new GXUser() { Id = Id.Value.ToString() };
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    private async ValueTask<ItemsProviderResult<GXUser>> GetItems(GXItemsProviderRequest request)
    {
        //Don't clear status or error is lost.
        Notifier?.ProgressStart();
        try
        {
            if (request.Removed)
            {
                filter.Removed = DateTimeOffset.MaxValue;
            }
            else
            {
                filter.Removed = null;
            }
            ListUsers req = new ListUsers()
                {
                    Index = request.StartIndex,
                    Count = request.Count,
                    Filter = filter,
                    OrderBy = request.OrderBy,
                    Descending = request.Descending,
                    AllUsers = request.ShowAllUserData
                };
            if (Count != 0)
            {
                req.Count = Count;
            }
            var ret = await Http.PostAsJson<ListUsersResponse>("api/User/List", req, request.CancellationToken);
            return new ItemsProviderResult<GXUser>(ret.Users, ret.Count);
        }
        catch (TaskCanceledException)
        {
            //Let the table component handle this.
            throw;
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
        return default;
    }

    /// <summary>
    /// Add new user.
    /// </summary>
    public void OnAdd()
    {
        try
        {
            Notifier.ClearStatus();
            ClientHelpers.NavigateTo(NavigationManager, Notifier, "/User/Add");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    /// <summary>
    /// Edit user.
    /// </summary>
    public void OnEdit()
    {
        try
        {
            Notifier.ClearStatus();
            if (table?.Active == null)
            {
                throw new Exception(Gurux.DLMS.AMI.Client.Properties.Resources.NoItemIsSelected);
            }
            ClientHelpers.NavigateTo(NavigationManager, Notifier, "/User/Edit/" + table.Active.Id);
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }


    /// <summary>
    /// Remove selected user.
    /// </summary>
    public void OnRemove()
    {
        try
        {
            if (table == null || !table.SingleOrDefault().Any())
            {
                throw new Exception(Gurux.DLMS.AMI.Client.Properties.Resources.NoItemIsSelected);
            }
            DeleteConfirmation?.Show(table?.SingleOrDefault()?.Select(s => s.UserName).ToArray());
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    /// <summary>
    /// Delete the selected users.
    /// </summary>
    public async Task OnDeleteConfirmation(ConfirmArgs args)
    {
        try
        {
            if (table != null && args.Confirm)
            {
                RemoveUser req = new RemoveUser()
                    {
                        Delete = args.Delete,
                        Ids = table.SingleOrDefault().Select(w => w.Id).ToArray()
                    };
                await Http.PostAsJson<RemoveUserResponse>("api/User/Delete", req);
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }


    /// <summary>
    /// Show user actions.
    /// </summary>
    public void OnActions()
    {
        try
        {
            Notifier.ClearStatus();
            if (table?.Active == null)
            {
                throw new Exception(Gurux.DLMS.AMI.Client.Properties.Resources.NoItemIsSelected);
            }
            Notifier.UpdateData(GXPages.Users, table.Active);
            ClientHelpers.NavigateTo(NavigationManager, Notifier, $"/userActions");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    /// <summary>
    /// Show user readers.
    /// </summary>
    public void OnAgents()
    {
        try
        {
            Notifier.ClearStatus();
            if (table?.Active == null)
            {
                throw new Exception(Gurux.DLMS.AMI.Client.Properties.Resources.NoItemIsSelected);
            }
            Notifier.UpdateData(GXPages.Users, table.Active);
            ClientHelpers.NavigateTo(NavigationManager, Notifier, $"/agents");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }

    public void Dispose()
    {
        Notifier.RemoveListener(this);
    }
}

